#include "CVbCounter.h"

#define CONTINUATION_CHAR '_'

CVbCounter::CVbCounter()
{
	QuoteStart = "\"";
	QuoteEnd = "\"";
	QuoteEscapeRear = '\"';
	casesensitive = false;

	exclude_SLOC.push_back("Loop"); // has to be staying alone
	exclude_SLOC.push_back("Else"); // has to be staying alone 
	exclude_SLOC.push_back("Do"); // has to be staying alone, e.g., not Do i = 5
	exclude_SLOC.push_back("Wend"); // staying alone

	exclude_SLOC_line.push_back("Next");
	exclude_SLOC_line.push_back("End");

	LineCommentStart.push_back("'");
	LineCommentStart.push_back("REM ");

	classtype = VB;
	language_name = "Visual_Basic";

	file_extension.push_back(".vb");
	file_extension.push_back(".frm");
	file_extension.push_back(".mod");
	file_extension.push_back(".cls");
	file_extension.push_back(".bas");
//	file_extension.push_back(".vbp");
	file_extension.push_back(".vbs");

	directive.push_back("#Const");
	directive.push_back("#If");
	directive.push_back("#Else");
	directive.push_back("#ElseIf");
	directive.push_back("#End");
	directive.push_back("#Region");
	directive.push_back("#ExternalSource");

	data_name_list.push_back("Boolean");
	data_name_list.push_back("Byte");
	data_name_list.push_back("Currency");
	data_name_list.push_back("Double");
	data_name_list.push_back("Date");
	data_name_list.push_back("Time");
	data_name_list.push_back("Integer");
	data_name_list.push_back("Item");
	data_name_list.push_back("Long");
	data_name_list.push_back("Object");
	data_name_list.push_back("Single");
	data_name_list.push_back("String");
	data_name_list.push_back("Variant");
	data_name_list.push_back("Const");
	data_name_list.push_back("Dim");
	data_name_list.push_back("Private");
	data_name_list.push_back("Public");
	data_name_list.push_back("ReDim");
	data_name_list.push_back("New");
	data_name_list.push_back("Static");
	data_name_list.push_back("Collection");
	data_name_list.push_back("Option");

	exec_name_list.push_back("Erase");
	exec_name_list.push_back("Add");
	exec_name_list.push_back("Remove");
	exec_name_list.push_back("Sub");
	exec_name_list.push_back("GoSub");
	exec_name_list.push_back("Return");
	exec_name_list.push_back("GoTo");
	exec_name_list.push_back("On");
	exec_name_list.push_back("DoEvents");
	exec_name_list.push_back("End");
	exec_name_list.push_back("Exit");
	exec_name_list.push_back("Stop");
	exec_name_list.push_back("Do");
	exec_name_list.push_back("Loop");
	exec_name_list.push_back("For");
	exec_name_list.push_back("Next");
	exec_name_list.push_back("While");
	exec_name_list.push_back("Wend");
	exec_name_list.push_back("With");
	exec_name_list.push_back("If");
	exec_name_list.push_back("Select");
	exec_name_list.push_back("Switch");
	exec_name_list.push_back("Call");
	exec_name_list.push_back("Function");
	exec_name_list.push_back("Format");
	exec_name_list.push_back("Str");
	exec_name_list.push_back("CBool");
	exec_name_list.push_back("CByte");
	exec_name_list.push_back("CCur");
	exec_name_list.push_back("CDate");
	exec_name_list.push_back("CDbl");
	exec_name_list.push_back("CDec");
	exec_name_list.push_back("CInt");
	exec_name_list.push_back("CStr");
	exec_name_list.push_back("CVar");
	exec_name_list.push_back("Fix");
	exec_name_list.push_back("Asc");
	exec_name_list.push_back("Val");
	exec_name_list.push_back("Now");
	exec_name_list.push_back("Timer");
	exec_name_list.push_back("ChDir");
	exec_name_list.push_back("FileCopy");
	exec_name_list.push_back("MkDir");
	exec_name_list.push_back("RmDir");
	exec_name_list.push_back("Name");
	exec_name_list.push_back("CurDir");
	exec_name_list.push_back("FileDateTime");
	exec_name_list.push_back("GetAttr");
	exec_name_list.push_back("FileLen");
	exec_name_list.push_back("Dir");
	exec_name_list.push_back("SetAttr");
	exec_name_list.push_back("Clear");
	exec_name_list.push_back("Error");
	exec_name_list.push_back("Raise");
	exec_name_list.push_back("On");
	exec_name_list.push_back("Resume");
	exec_name_list.push_back("IsError");
	exec_name_list.push_back("Open");
	exec_name_list.push_back("Close");
	exec_name_list.push_back("Reset");
	exec_name_list.push_back("Format");
	exec_name_list.push_back("Print");
	exec_name_list.push_back("Spc");
	exec_name_list.push_back("Tab");
	exec_name_list.push_back("Width");
	exec_name_list.push_back("FileAttr");
	exec_name_list.push_back("FreeFile");
	exec_name_list.push_back("Loc");
	exec_name_list.push_back("LOF");
	exec_name_list.push_back("Seek");
	exec_name_list.push_back("Then");
	exec_name_list.push_back("Kill");
	exec_name_list.push_back("Lock");
	exec_name_list.push_back("Unlock");
	exec_name_list.push_back("Name");
	exec_name_list.push_back("Get");
	exec_name_list.push_back("Input");
	exec_name_list.push_back("Line");
	exec_name_list.push_back("Put");
	exec_name_list.push_back("Write");
	exec_name_list.push_back("Randomize");
	exec_name_list.push_back("Rnd");
	exec_name_list.push_back("AppActivate");
	exec_name_list.push_back("Shell");
	exec_name_list.push_back("SendKeys");
	exec_name_list.push_back("Beep");
	exec_name_list.push_back("Environ");
	exec_name_list.push_back("Command");
	exec_name_list.push_back("CreateObject");
	exec_name_list.push_back("GetObject");
	exec_name_list.push_back("Else");
	exec_name_list.push_back("Len");
	exec_name_list.push_back("InStr");
	exec_name_list.push_back("Left");
	exec_name_list.push_back("Mid");
	exec_name_list.push_back("Right");
	exec_name_list.push_back("Server");
}

int CVbCounter::CountDirectiveSLOC(filemap* fmap, results* result, filemap* fmapBak)
{
	bool contd = false, trunc_flag = false;
	size_t idx, strSize;
	if(classtype == DATAFILE) return 0;
	int cnt = 0;
	string  exclude = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$";
	string strDirLine = "";

	for (filemap::iterator iter = fmap->begin(); iter!=fmap->end(); iter++)
	{
		if (CUtil::CheckBlank(iter->line)) continue;

		cnt=0;
		CUtil::CountTally(" " + iter->line, directive, cnt, 1, exclude, "", "", &directive_count, result->duplicate);

		if (!contd)
		{	// if not a continuation of a previous directive
			for(vector<string>::iterator viter = directive.begin(); viter != directive.end(); viter++)
			{
				if ((idx = iter->line.find((*viter), 0)) != string::npos && idx == 0)
				{
					contd = true;
					break;
   		        }
        	}
			if (contd)
			{
				result->directive_lines[PHY]++;
				strSize = CUtil::TruncateLine(iter->line.length(), 0, result->lsloc_truncate, trunc_flag);
				if (strSize > 0)
					strDirLine = iter->line.substr(0, strSize);
			}	// incrementing the physical directive lines
 		}
		else
		{	// continuation of a previous directive
			strSize = CUtil::TruncateLine(iter->line.length(), strDirLine.length(), result->lsloc_truncate, trunc_flag);
			if (strSize > 0)
				strDirLine += "\n" + iter->line.substr(0, strSize);
			result->directive_lines[PHY]++;	// incrementing the physical lines for a directive
		}
	
		if (contd)
		{	// if a directive or continuation of a directive
			if (iter->line[iter->line.length()-1] != '_')
			{
				contd = false;
				result->directive_lines[LOG]++;
				result->addSLOC(strDirLine, trunc_flag);	//add another Logical directive line, should also have type
			}	// if no continuation symbol found
			iter->line = "";
		}
	}
	return 1;
}

int CVbCounter::LanguageSpecificProcess(filemap* fmap, results* result, filemap* fmapBak)
{
	string strLSLOC = "";
    string strLSLOCBak = "";

	filemap::iterator fit, fitbak;
	string line, lineBak;
	size_t pos, prev_pos, strSize;
	int cnt = 0;	//for CUtil::CountTally use

	// two strings used for string match
	string exclude = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$";
	string special = "[]()+/-*<>=,@&~!^?:%{}";

	string tmpstr;
	bool isDataLine = false;
	bool line_continued = false;
	bool line_skipped;
	bool trunc_flag = false;

	for (fit = fmap->begin(), fitbak = fmapBak->begin(); 
		fit != fmap->end(); fit++, fitbak++)
	{ 
		line = fit->line;
		lineBak = fitbak->line;

		if (CUtil::CheckBlank(line))
		{
			continue;
		}	

		//delete the line number
		pos = line.find_first_of(":");
		if ((pos == 0) || (pos != string::npos && CUtil::isInteger(line.substr(0,pos))))
		{
			line = line.substr(pos + 1);
			lineBak = lineBak.substr(pos + 1);
		}

		prev_pos = 0;

		for (size_t i = 0; i < line.size(); i++)
		{
			if ((line[i] == ':') || (i == line.size() - 1))
			{
				tmpstr = CUtil::TrimString(line.substr(prev_pos, i - prev_pos + 1));

				// Exclude SLOC defined in the exclude_SLOC
				line_skipped = false;
				for (vector<string>::iterator stri = exclude_SLOC.begin(); stri != exclude_SLOC.end(); stri++)
				{
					if (tmpstr.compare(*stri) == 0)
					{
						line_skipped = true;
						break;
					}
				}
				if (line_skipped) continue;

				line_skipped = false;
				// Exclude SLOC starting with Next, End
				for (StringVector::iterator stri = exclude_SLOC_line.begin(); stri != exclude_SLOC_line.end(); stri++)
				{
					if (CUtil::FindKeyword(tmpstr, *stri) != string::npos)
					{
						line_skipped = true;
						break;
					}
				}

				if (line_skipped) continue;

				strSize = CUtil::TruncateLine(i + 1 - prev_pos, strLSLOC.length(), result->lsloc_truncate, trunc_flag);
				if (strSize > 0)
				{
					strLSLOC += line.substr(prev_pos, strSize);
					strLSLOCBak += lineBak.substr(prev_pos, strSize);
				}

				line_continued = ((i == line.size() - 1) && tmpstr[tmpstr.length() - 1] == CONTINUATION_CHAR);				
				if (line_continued) continue;

				cnt = 0;
				CUtil::CountTally(strLSLOC, data_name_list, cnt, 1, exclude, "", "", &data_name_count, result->duplicate);
				if (cnt > 0)
				{
					isDataLine = true;
					result->data_lines[LOG]++;					
				}
				else
				{
					isDataLine = false;
					result->exec_lines[LOG]++;
				}

				result->addSLOC(strLSLOCBak, trunc_flag);  // add one logical SLOC to the list
				strLSLOCBak = "";
				strLSLOC = "";

			 	prev_pos = i + 1;
			}

            if (special.find_first_of(line[i]) != string::npos) 
			{
				line[i] = ' ';
			}
		}	//for
		
		if (isDataLine)
		{	// Update physical SLOC lines
			result->data_lines[PHY]++;
		}
		else
		{
			result->exec_lines[PHY]++;
		}
	}	//for(fit)
	return 1;
}

CVbsPhpCounter::CVbsPhpCounter()
{
	classtype = VBS_PHP;
	language_name = "VBScript/PHP";

	file_extension.clear();
	file_extension.push_back(".*vbsphp");
}

CVbsHtmlCounter::CVbsHtmlCounter()
{
	classtype = VBS_HTML;
	language_name = "VBScript/HTML";

	file_extension.clear();
	file_extension.push_back(".*vbshtm");
}

CVbsJspCounter::CVbsJspCounter()
{
	classtype = VBS_JSP;
	language_name = "VBScript/JSP";

	file_extension.clear();
	file_extension.push_back(".*vbsjsp");
}

CVbsAspServerCounter::CVbsAspServerCounter()
{
	classtype = VBS_ASP_S;
	language_name = "VBScript/ASP server";

	file_extension.clear();
	file_extension.push_back(".*vbsasps");
}

CVbsAspClientCounter::CVbsAspClientCounter()
{
	classtype = VBS_ASP_C;
	language_name = "VBScript/ASP client)";

	file_extension.clear();
	file_extension.push_back(".*vbsaspc");
}
